#include "dictionary_ctrl.h"

char *m_replyId = NULL;

/// @brief 向上级发送进度
/// @param code
/// @param progress
/// @return
bool send_progress_V2(int code, int progress, ST_IOTA_LOG_RES *progressDecs)
{
    cJSON *json = NULL;
    cJSON *body = NULL;
    char *pcJson;
    json = cJSON_CreateObject();
    body = cJSON_CreateObject();
    char cTime[128] = {0};
    int ret = systemDate2(cTime);
    if (progressDecs)
    {
        // json
        cJSON_AddStringToObject(json, "mid", progressDecs->iMid);
        cJSON_AddNumberToObject(json, "code", code);
        cJSON_AddStringToObject(json, "deviceSn", progressDecs->deviceSn);
        cJSON_AddStringToObject(json, "replyId", progressDecs->replyId);
        cJSON_AddStringToObject(json, "zone", progressDecs->zone);
        cJSON_AddStringToObject(json, "node", progressDecs->node);
        if (strlen(progressDecs->requestID) > 0)
        {
            cJSON_AddStringToObject(json, "requestId", progressDecs->requestID);
        }
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", progressDecs->deviceID);
        cJSON_AddNumberToObject(json, "installProgress", progress);
        if (progressDecs->body != NULL)
        {
            IOTA_DICTIONARY_PROGRESS *st_body = progressDecs->body;
            char total[32] = {0};
            char now[32] = {0};
            sprintf(total, "%ld", st_body->total);
            sprintf(now, "%ld", st_body->now);
            cJSON_AddStringToObject(body, "now", now);
            cJSON_AddStringToObject(body, "total", total);
            cJSON_AddNumberToObject(body, "time", st_body->time);
            cJSON_AddStringToObject(body, "speed", st_body->speed);
            cJSON_AddStringToObject(body, "filename", st_body->filename);
            cJSON_AddItemToObject(json, "body", body);
        }

        pcJson = cJSON_PrintUnformatted(json);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", pcJson, strlen(pcJson));
        while (ret < 0)
        {
            ret = IOTA_SendMqtt("/v1/devices/dictionary/response", pcJson, strlen(pcJson));
            sleep(5);
        }
        dzlog_debug("code = %d progress = %d", code, progress);
        cJSON_Delete(json);
        free_s(pcJson);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_GetDictionaryTree(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        // pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);

        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_PARAM *st_param = pcStatusDecs->param;
            st_param->path = strdup(cJSON_GetObjectItem(param, "path")->valuestring);
            if (cJSON_HasObjectItem(param, "fileName"))
            {
                st_param->fileName = strdup(cJSON_GetObjectItem(param, "fileName")->valuestring);
            }
            else
            {
                st_param->fileName = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_DictionaryDetele(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_PARAM *st_param = pcStatusDecs->param;
            if (cJSON_HasObjectItem(param, "path"))
            {
                st_param->path = strdup(cJSON_GetObjectItem(param, "path")->valuestring);
            }
            else
            {
                st_param->path = NULL;
            }            
            
            if (cJSON_HasObjectItem(param, "fileName"))
            {
                st_param->fileName = strdup(cJSON_GetObjectItem(param, "fileName")->valuestring);
            }
            else
            {
                st_param->fileName = NULL;
            }
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    } 
}

bool JsonToStruct_UploadFiles(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_FILE_PARAM *st_param = pcStatusDecs->param;
            st_param->file = strdup(cJSON_GetObjectItem(param, "file")->valuestring);
        }
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_DownloadFile(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_DOWNLOAD_PARAM *st_param = pcStatusDecs->param;
            st_param->fileId = strdup(cJSON_GetObjectItem(param, "fileId")->valuestring);
            st_param->filename = strdup(cJSON_GetObjectItem(param, "filename")->valuestring);
            st_param->size = cJSON_GetObjectItem(param, "size")->valueint;
            st_param->digestAlgorithm = strdup(cJSON_GetObjectItem(param, "digestAlgorithm")->valuestring);
            st_param->digest = strdup(cJSON_GetObjectItem(param, "digest")->valuestring);
            st_param->fileLink = strdup(cJSON_GetObjectItem(param, "fileLink")->valuestring);
        }
        cJSON_Delete(json);
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_CopyFile(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_COPY_PARAM *st_param = pcStatusDecs->param;
            st_param->srcpath = strdup(cJSON_GetObjectItem(param, "srcpath")->valuestring);
            st_param->descpath = strdup(cJSON_GetObjectItem(param, "descpath")->valuestring);
            st_param->isfile = cJSON_GetObjectItem(param, "isfile")->valueint;
        }
        cJSON_Delete(json);
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_GetDicSize(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_GETDICSIZE_PARAM *st_param = pcStatusDecs->param;
            st_param->path = strdup(cJSON_GetObjectItem(param, "path")->valuestring);
        }
        cJSON_Delete(json);
    }
    else
    {
        return false;
    }
}

bool JsonToStruct_Break(char *pcJson, ST_IOTA_LOG *pcStatusDecs)
{
    cJSON *json = NULL;
    cJSON *param = NULL;
    json = cJSON_Parse(pcJson);
    if (json)
    {
        pcStatusDecs->iMid = strdup(cJSON_GetObjectItem(json, "mid")->valuestring);
        pcStatusDecs->deviceSn = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        pcStatusDecs->Servicename = strdup(cJSON_GetObjectItem(json, "service")->valuestring);
        pcStatusDecs->zone = strdup(cJSON_GetObjectItem(json, "zone")->valuestring);
        pcStatusDecs->node = strdup(cJSON_GetObjectItem(json, "node")->valuestring);
        pcStatusDecs->msgTime = strdup(cJSON_GetObjectItem(json, "msgTime")->valuestring);
        pcStatusDecs->deviceID = strdup(cJSON_GetObjectItem(json, "deviceSn")->valuestring);
        if (cJSON_HasObjectItem(json, "requestId") && strlen(cJSON_GetObjectItem(json, "requestId")->valuestring) > 0)
        {
            pcStatusDecs->requestID = strdup(cJSON_GetObjectItem(json, "requestId")->valuestring);
        }
        else
        {
            pcStatusDecs->requestID = strdup("com.jxtech.iot_ops - tasks");
        }
        if (cJSON_HasObjectItem(json, "params"))
        {
            param = cJSON_GetObjectItem(json, "params");
            IOTA_DICTIONARY_BREAK_PARAM *st_param = pcStatusDecs->param;
            st_param->filename = strdup(cJSON_GetObjectItem(param, "filename")->valuestring);
        }

        cJSON_Delete(json);
    }
    return true;
}

bool StructToJson_GetDictionaryTree(char **pcJson, ST_IOTA_LOG_RES *pcStatusDecs, int count)
{
    if (pcStatusDecs)
    {
        cJSON *json = NULL;
        cJSON *body = NULL;
        json = cJSON_CreateObject();
        body = cJSON_CreateArray();
        char cTime[128] = {0};
        int ret = systemDate2(cTime);
        // json
        cJSON_AddStringToObject(json, "mid", pcStatusDecs->iMid);
        cJSON_AddStringToObject(json, "deviceSn", pcStatusDecs->deviceSn);
        cJSON_AddNumberToObject(json, "code", pcStatusDecs->code);
        cJSON_AddStringToObject(json, "replyId", pcStatusDecs->replyId);
        cJSON_AddStringToObject(json, "zone", pcStatusDecs->zone);
        cJSON_AddStringToObject(json, "node", pcStatusDecs->node);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", pcStatusDecs->deviceID);

        // body
        IOTA_DICTIONARY_INFO *st_body = (IOTA_DICTIONARY_INFO *)pcStatusDecs->body;
        if (count > 0)
        {
            int i = 0;
            for (i = 0; i < count; i++)
            {
                cJSON *file = cJSON_CreateObject();
                cJSON_AddStringToObject(file, "filename", st_body[i].filename);
                cJSON_AddStringToObject(file, "user", st_body[i].user);
                cJSON_AddStringToObject(file, "group", st_body[i].group);
                cJSON_AddStringToObject(file, "permission", st_body[i].permission);
                cJSON_AddStringToObject(file, "updatetime", st_body[i].updatetime);
                cJSON_AddStringToObject(file, "type", st_body[i].type);
                cJSON_AddNumberToObject(file, "size", st_body[i].size);
                cJSON_AddItemToArray(body, file);
            }
        }

        cJSON_AddItemToObject(json, "body", body);
        *pcJson = cJSON_PrintUnformatted(json);

        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}

bool StructToJson_GetDictionarySize(char **pcJson, ST_IOTA_LOG_RES *pcStatusDecs)
{
    if (pcStatusDecs)
    {
        cJSON *json = NULL;
        cJSON *body = NULL;
        json = cJSON_CreateObject();
        char cTime[32] = {0};
        int ret = systemDate2(cTime);
        // json
        cJSON_AddStringToObject(json, "mid", pcStatusDecs->iMid);
        cJSON_AddStringToObject(json, "deviceSn", pcStatusDecs->deviceSn);
        cJSON_AddNumberToObject(json, "code", pcStatusDecs->code);
        cJSON_AddStringToObject(json, "replyId", pcStatusDecs->replyId);
        cJSON_AddStringToObject(json, "zone", pcStatusDecs->zone);
        cJSON_AddStringToObject(json, "node", pcStatusDecs->node);
        cJSON_AddStringToObject(json, "msgTime", cTime);
        cJSON_AddStringToObject(json, "deviceId", pcStatusDecs->deviceSn);
        // body
        IOTA_DICTIONARY_SIZE *st_body = (IOTA_DICTIONARY_SIZE *)pcStatusDecs->body;
        cJSON_AddItemToObject(json, "body", body = cJSON_CreateObject());
        cJSON_AddStringToObject(body, "path", st_body->path);
        cJSON_AddStringToObject(body, "size", st_body->size);

        *pcJson = cJSON_PrintUnformatted(json);
        cJSON_Delete(json);
        return true;
    }
    else
    {
        return false;
    }
}
// 获取文件信息，类似ls -l
int get_file_info(const char *path, IOTA_DICTIONARY_INFO *file)
{
    struct stat file_stat;
    struct passwd *pw;
    struct group *gr;

    if (lstat(path, &file_stat) == -1)
    {
        int error = errno;
        dzlog_error("getpathinfo %d error %s", path, strerror(error));
        return 0;
    }
    long sizetmp = -1;

    // 文件大小
    sizetmp = file_stat.st_size;

    // 文件权限类型和列表
    char mode[10] = {0};
    char typestr[20] = {0};
    // 文件类型
    if (S_ISREG(file_stat.st_mode))
    {
        mode[0] = '-';
        if (strchr(path, '.') == NULL)
        {
            sprintf(typestr, "file not download");
            dzlog_info("file can not download %s", path);
        }
        else
        {
            sprintf(typestr, "file");
        }
    }
    else if (S_ISDIR(file_stat.st_mode))
    {
        mode[0] = 'd';
        sprintf(typestr, "directory");
    }
    else if (S_ISLNK(file_stat.st_mode))
    {
        mode[0] = 'l';
        sprintf(typestr, "link");
        struct stat target_stat;
        if (stat(path, &target_stat) == 0)
        {
            if (S_ISDIR(target_stat.st_mode))
            {
                sprintf(typestr, "directory");
            }
            else if (S_ISREG(target_stat.st_mode))
            {
                if (strchr(path, '.') == NULL)
                {
                    sprintf(typestr, "file not download");
                    dzlog_info("file can not download %s", path);
                }
                else
                {
                    sprintf(typestr, "file");
                }
            }
        }
    }
    else if (S_ISBLK(file_stat.st_mode))
    {
        mode[0] = 'b';
        sprintf(typestr, "block");
    }
    else if (S_ISCHR(file_stat.st_mode))
    {
        mode[0] = 'c';
        sprintf(typestr, "character");
    }
    else if (S_ISFIFO(file_stat.st_mode))
    {
        mode[0] = 'p';
        sprintf(typestr, "fifo");
    }
    else if (S_ISSOCK(file_stat.st_mode))
    {
        mode[0] = 's';
        sprintf(typestr, "socket");
    }
    else
    {
        mode[0] = '?';
        sprintf(typestr, "file");
    }
    // 权限
    mode[1] = (file_stat.st_mode & S_IRUSR) ? 'r' : '-';
    mode[2] = (file_stat.st_mode & S_IWUSR) ? 'w' : '-';
    mode[3] = (file_stat.st_mode & S_IXUSR) ? 'x' : '-';
    mode[4] = (file_stat.st_mode & S_IRGRP) ? 'r' : '-';
    mode[5] = (file_stat.st_mode & S_IWGRP) ? 'w' : '-';
    mode[6] = (file_stat.st_mode & S_IXGRP) ? 'x' : '-';
    mode[7] = (file_stat.st_mode & S_IROTH) ? 'r' : '-';
    mode[8] = (file_stat.st_mode & S_IWOTH) ? 'w' : '-';
    mode[9] = (file_stat.st_mode & S_IXOTH) ? 'x' : '-';
    memset(file, 0, sizeof(IOTA_DICTIONARY_INFO));
    strcpy(file->permission, mode);
    file->permission[10] = '\0';
    strcpy(file->type, typestr);
    // 硬链接数
    long links = file_stat.st_nlink;
    // 所有者
    pw = getpwuid(file_stat.st_uid);
    if (pw != NULL)
    {
        if (pw->pw_name != NULL && strlen(pw->pw_name) != 0)
        {
            strcpy(file->user, pw->pw_name);
        }
    }

    // 所属组
    gr = getgrgid(file_stat.st_gid);
    if (gr != NULL)
    {
        strcpy(file->group, gr->gr_name);
    }

    // 文件大小
    file->size = sizetmp;
    // 修改时间
    char time_buf[64];
    // strftime(time_buf, sizeof(time_buf), "%b %d %H:%M", localtime(&file_stat.st_mtime));
    strftime(time_buf, sizeof(time_buf), "%Y-%m-%d %H:%M:%S", localtime(&file_stat.st_mtime));
    strcpy(file->updatetime, time_buf);
    return 1;
}

/// @brief 显示当前目录下的所有文件
/// @param pJson
/// @return
int dictionary_tree(char *pJson)
{
    dzlog_info("dictionary_tree start");
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_PARAM param;
    log.param = &param;
    JsonToStruct_GetDictionaryTree(pJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.zone = log.zone;
    log_res.requestID = NULL;
    bool isError = false;
    struct dirent **entries;

    int i = 0;

    int num_entries = scandir(param.path, &entries, NULL, alphasort);
    if (num_entries == -1)
    {
        int error = errno;
        dzlog_error("scan path %d error %s", param.path, strerror(error));
        isError = true;
        log_res.code = 500;
        goto Uerror;
    }
    else
    {
        IOTA_DICTIONARY_INFO file_info[num_entries - 2];
        log_res.body = file_info;
        int count = 0;
        for (i = 0; i < num_entries; i++)
        {
            if (strcmp(entries[i]->d_name, ".") == 0 || strcmp(entries[i]->d_name, "..") == 0)
            {
                free(entries[i]);
                continue;
            }

            if (param.fileName != NULL && strstr(entries[i]->d_name, param.fileName) == NULL)
            {
                free(entries[i]);
                continue;
            }

            IOTA_DICTIONARY_INFO file_tmp;
            char path[1024];
            snprintf(path, sizeof(path), "%s/%s", param.path, entries[i]->d_name);

            if (get_file_info(path, &file_tmp) != 1)
            {
                free(entries[i]);
                continue;
            }
            // 赋值
            strcpy(file_info[count].filename, entries[i]->d_name);
            free(entries[i]);

            strcpy(file_info[count].group, file_tmp.group);
            strcpy(file_info[count].permission, file_tmp.permission);
            strcpy(file_info[count].updatetime, file_tmp.updatetime);
            strcpy(file_info[count].user, file_tmp.user);
            strcpy(file_info[count].type, file_tmp.type);
            file_info[count].size = file_tmp.size;
            count++;
        }

        log_res.code = 200;
        StructToJson_GetDictionaryTree(&psJson, &log_res, count);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }
Uerror:
    if (isError)
    {
        log_res.body = "update error";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.zone);
    free_s(psJson);
    free_s(param.path);
    free_s(entries);

    return 0;
}

/// @brief 文件上传
/// @param arg
/// @return
int dictionary_file_upload(char *arg)
{
    // 上传文件
    ProgressInfo *info = (ProgressInfo *)arg;
    ST_IOTA_LOGIN_RES_V1 login = { 0 };
    ST_IOTA_AUTH_RES_V1 auth;
    ST_IOTA_FILE_RES *file = malloc(sizeof(ST_IOTA_FILE_RES));
    file->data = NULL;
    login.data = &auth;
    // 用户账户登录
    file->resultCode = httpFileServerLoginWithUser_v1(&login, LOGIN_USER, LOGIN_PASSWORD, "iotplatform", "password");
    if (file->resultCode)
    {
        dzlog_error("login fileserver error");
        free_s(login.message);
        return -1;
    }

    // 上传文件

    httpFileServerUploadFile_v1(info->filename, &auth, file, info);
    free_s(auth.nonce);
    free_s(auth.token);
    free_s(auth.timestamp);
    free_s(login.message);
    pthread_exit((void *)file);
}

/// @brief 文件提取 设备->后端
/// @param pcJson
/// @return
int dictionary_upload_pthread(char *pcJson)
{
    ST_IOTA_LOG log;

    IOTA_DICTIONARY_FILE_PARAM param;
    log.param = &param;
    JsonToStruct_UploadFiles(pcJson, &log);
    char *psJson = NULL;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    ST_IOTA_LOG_BODY log_body;

    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    log_res.body = NULL;
    bool isError = false;
    int ret = 0;

    if (calculate_file_size(param.file) < 0)
    {
        log_res.code = 424;
        dzlog_info("no file is here %s", param.file);
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        goto Llogin;
    }

    // 开始下载
    log_res.code = 100;
    dzlog_info("update file:%s", param.file);
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    free_s(psJson);
    //  检查是否是目录
    
    struct stat file_stat;
    if (lstat(param.file, &file_stat) == -1)
    {
        int error = errno;
        dzlog_error("can not find file %s %s", param.file, strerror(error));
        log_res.code = 521;
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        goto Llogin;
    }

    if (S_ISDIR(file_stat.st_mode))
    {
        int error = errno;
        dzlog_error("is a dictionary %s", param.file);
        log_res.code = 500;
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        goto Llogin;
    }
    int *iRet = NULL;

    ProgressInfo info;
    // 压缩日志文件
    char tar[200] = {0};
    strcpy(info.filename, param.file);
    // 检测文件是否为日志文件
    size_t len = strlen(param.file);
    if (len > 4 && strcmp(param.file + len - 4, ".log") == 0)
    {
        snprintf(tar, sizeof(tar), "%s.tar.gz", param.file);
        // 压缩日志文件
        char cmd[200] = {0};
        snprintf(cmd, sizeof(cmd), "tar -czvf %s %s", tar, param.file);
        int ret = system(cmd);
        if (ret != 0)
        {
            dzlog_error("compress log file error");
        }
        else
        {
            free_s(param.file);
            param.file = tar;
            strcpy(info.filename, tar);
        }
    }
    dzlog_info("upload file:%s", param.file);
    memset(info.md5, 0, sizeof(info.md5));
    info.stop = 0;
    info.ret = 0;
    info.Progress = 0;
    info.Bytes = 0;
    info.filesize = 0;
    info.action = 2;
    // token登录获取发送文件信息
    // ST_IOTA_AUTH_RES auth;
    // ret = httpFileServerGetHeader_v1(access_token, &auth);
    // if (ret < 0)
    // {
    //     dzlog_error("access_token error");
    //     isError = true;
    //     goto Lauth;
    // }

    // 分线程
    pthread_t thread;

    // 创建线程
    pthread_create(&thread, NULL, dictionary_file_upload, &info);

    // 读取进度
    int retry = 0;
    int progress = 0;
    ST_IOTA_FILE_RES *file = NULL;
    int last_size = 0;

    // 截取文件名
    char *last_slash = strrchr(param.file, '/');
    char result[100];
    strncpy(result, last_slash + 1, sizeof(result));
    result[sizeof(result) - 1] = '\0';
    printf("截取后的字符串： %s", result);

    while (progress <= 100)
    {

        if (retry > 30)
        {
            dzlog_error("Upload error time out");
            break;
        }
        sleep(1);
        dzlog_info("info.ret = %d", info.ret);
        if (info.ret < 0)
        {
            dzlog_error("Upload error progress thread exit");
            break;
        }
        if (progress == (int)info.Progress)
        {
            retry++;
            dzlog_info("Upload retry %d", retry);
            continue;
        }
        else
        {
            retry = 0;
        }
        progress = (int)info.Progress;
        IOTA_DICTIONARY_PROGRESS progress_info;

        progress_info.total = info.filesize;
        progress_info.now = info.Bytes;
        if (last_slash)
        {
            strcpy(progress_info.filename, result);
        }
        else
        {
            strcpy(progress_info.filename, param.file);
        }
        // 取后两位
        int tmp = (info.Bytes - last_size) / 1024 * 100;
        float speed = (float)tmp / 100; // KB/s

        speed = (speed < 0.1) ? 0.1 : speed; // 设置最小速度防止除0
        sprintf(progress_info.speed, "%.2f", speed);
        // 计算剩余时间(秒)
        if (speed < 0.1)
        {
            progress_info.time = 0;
        }
        else
        {
            float remaining_bytes = info.filesize - info.Bytes;
            progress_info.time = (int)(remaining_bytes / 1024 / speed); // 转换为秒
        }

        log_res.body = &progress_info;

        last_size = info.Bytes;
        dzlog_debug("progress = %d downloadProgress = %f", progress, info.Progress);
        GF_GetGUID(uid);
        send_progress_V2(115, progress, &log_res);
        if (progress == 100)
        {
            break;
        }
        if (info.stop == 1)
        {
            send_progress_V2(116, progress, &log_res);
            break;
        }
    }

    // 等待线程结束
    pthread_join(thread, (void **)&file);

    if (file->resultCode < 0)
    {
        dzlog_error("file upload error");

        if (file->resultCode == -1)
        {
            dzlog_error("file upload error 11");
            log_res.code = 520;
            dzlog_error("extract log error: Timeout was reached");
            dzlog_error("file upload error 22");
            StructToJson_LogUploadRes(&psJson, &log_res, true);
            dzlog_error("file upload error 33");
            ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
            dzlog_error("file upload error 44");
        }
        goto Lfile;
    }

    // 被中断的
    if (info.stop == 1)
    {
        log_res.code = 202;
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        goto Lfile;
    }

    if (file->resultCode != 200)
    {
        log_res.code = 522;
        log_res.body = "extract log success: no data";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        goto Lfile;
    }

    // 从data里面获取filedID
    ST_IOTA_FILE_DATA file_data;
    JsonToStruct_LogFileData(file->data, &file_data);
    char md5[100] = {0};

    calculate_md5(param.file, md5);
    log_body.size = file_data.fileSize;
    log_body.md5 = md5;
    log_body.filed = file_data.fileId;
    log_body.FileName = param.file;
    log_res.body = &log_body;
    log_res.node = file_data.node;
    log_res.zone = file_data.zone;
    if (last_slash)
    {
        log_body.FileName = result;
    }
    else
    {
        printf("未找到/字符");
    }

    GF_GetGUID(uid);
    log_res.code = 200;
    StructToJson_LogUploadRes(&psJson, &log_res, false);

    IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));

Lfile:
    free_s(file->message);
    free_s(file->data);
    free_s(file);
    free_s(file_data.fileId);
    free_s(file_data.node);
    free_s(file_data.zone);
// Lauth:
//     free_s(psJson);
Llogin:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    if (tar[0] == 0)
    {
        free_s(param.file);
    }
    else
    {
        char cmd[200] = {0};
        snprintf(cmd, sizeof(cmd), "rm -f %s", tar);
        system(cmd);
    }
    free_s(psJson);
    free_s(pcJson);

    return 0;
}

int dictionary_upload(char *pcJson)
{
    // 分线程
    pthread_t thread;
    pthread_attr_t attr;
    char *psJson = strdup(pcJson);
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, dictionary_upload_pthread, psJson);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);
    return 0;
}

/// @brief 文件下载
/// @param arg
/// @return
int dictionary_file_download(char *arg)
{
    // 下载文件
    ProgressInfo *info = (ProgressInfo *)arg;
    int *ret = malloc(sizeof(int));
    *ret = -1;
    *ret = file_download(info->filename, info);
    dzlog_info("file_download ret = %d", *ret);
    info->ret = *ret;
    pthread_exit((void *)ret);
}

/// @brief 文件下载指令，主要是分线程
/// @param pcJson
/// @return
int dictionary_download_pthread(char *pcJson)
{
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_DOWNLOAD_PARAM param;
    log.param = &param;
    JsonToStruct_DownloadFile(pcJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;

    // 文件重复和文件下载占用的时候将这个打回去
    // if (strcmp(info.fileid, param.fileId) == 0)
    // {
    //     isError = true;
    //     log_res.code = 421;
    //     goto Uerror;
    // }
    // if (strlen(info.fileid) != 0)
    // {
    //     isError = true;
    //     log_res.code = 423;
    //     goto Uerror;
    // }
    dzlog_info("dictionary_download_pthread param.size[%d]", param.size);
    if (param.size <= 0)
    {
        isError = true;
        log_res.code = 400;
        goto Uerror;
    }

    if (calculate_file_size(param.filename) >= 0)
    {
        dzlog_info("calculate_file_size > 0");
        if (remove(param.filename) != 0)
        {
            dzlog_error("remove %s error %s", param.filename, strerror(errno));
            isError = true;
            log_res.code = 524;
            goto Uerror;
        }
    }
    dzlog_info("dictionary_download_pthread start 1");
    // 开始下载
    log_res.code = 100;
    log_res.body = "now is download";
    dzlog_info("Start download:%s", param.filename);
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    int ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    free_s(psJson);
    dzlog_info("dictionary_download_pthread start 2");
    ProgressInfo info;

    strcpy(info.filename, param.filename);
    strcpy(info.fileid, param.fileId);
    strcpy(info.md5, param.digest);
    info.filesize = param.size;
    // 1 下载 2 上传
    info.action = 1;
    info.ret = 0;
    info.Progress = 0;
    info.Bytes = 0;
    info.Bytes_bak = 0;
    info.stop = 0;
    // 分线程
    pthread_t thread;
    // pthread_attr_t attr;

    // 初始化线程属性
    // pthread_attr_init(&attr);

    // 将线程设置为分离状态
    // pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, NULL, dictionary_file_download, &info);
    // 销毁线程属性对象
    // pthread_attr_destroy(&attr);

    // 读取进度
    int retry = 0;
    int progress = 0;
    int *iRet = NULL;
    int last_size = 0;
    int sleep_time = 1;

    char *last_slash = strrchr(param.filename, '/');
    char result[100];
    strncpy(result, last_slash + 1, sizeof(result));
    result[sizeof(result) - 1] = '\0';
    printf("截取后的字符串： %s", result);

    while (progress <= 100)
    {
        if (retry > 315)
        {
            dzlog_error("download error time out");
            break;
        }
        sleep(sleep_time);

        if (progress == (int)info.Progress || ((int)info.Progress == 0 && progress != 0))
        {
            retry++;
            dzlog_info("download retry %d", retry);
            continue;
        }
        else
        {
            retry = 0;
        }
        if (info.Progress > progress)
        {
            progress = (int)info.Progress;
        }
        dzlog_debug("progress = %d downloadProgress = %f", progress, info.Progress);

        IOTA_DICTIONARY_PROGRESS progress_info;
        float speed = (info.Bytes - last_size) / 1024 / sleep_time; // KB/s
        sprintf(progress_info.speed, "%.2f", speed);
        progress_info.total = info.filesize;
        progress_info.now = info.Bytes;
        progress_info.time = (int)(info.filesize - info.Bytes) / (speed * 1024);

        if (last_slash)
        {
            strcpy(progress_info.filename, result);
        }
        else
        {
            strcpy(progress_info.filename, param.filename);
        }

        last_size = info.Bytes;
        log_res.body = &progress_info;
        GF_GetGUID(uid);
        send_progress_V2(115, progress, &log_res);
        if (progress == 100)
        {
            break;
        }
        if (progress_info.time < 0)
        {
            dzlog_debug(" progress_info.time[%d]", progress_info.time);
            retry++;
            continue;
        }
        if (info.stop == 1)
        {
            send_progress_V2(116, progress, &log_res);
            break;
        }
    }

    // off_t cur_size = 0;
    // int flag = 0;
    // while (cur_size < param.size)
    // { /*
    //      sleep(5);
    //      if (retry > 60)
    //      {
    //          dzlog_error("download error time out");
    //          break;
    //      }
    //      if (progress == (int)info.downloadProgress)
    //      {
    //          retry++;
    //          dzlog_info("download retry %d", retry);
    //          continue;
    //      }
    //      else
    //      {
    //          retry = 0;
    //      }
    //      progress = (int)info.downloadProgress;
    //      dzlog_debug("ota_download progress = %d downloadProgress = %f", progress, info.downloadProgress);
    //      memset(uid, 0, 64);
    //      GF_GetGUID(uid);
    //      log_res.iMid = uid;
    //      send_progress(115, progress, &log_res);
    //      if (progress == 100)
    //      {
    //          break;
    //      }*/
    //     sleep(5);
    //     struct stat file_inf = {0};
    //     stat(param.filename, &file_inf);
    //     if (cur_size == file_inf.st_size)
    //     {
    //         retry++;
    //         if (retry > 60)
    //         {
    //             flag = 1;
    //             break;
    //         }
    //     }
    //     cur_size = file_inf.st_size;
    //     dzlog_info("param.filename[%s], size = %ld", param.filename, file_inf.st_size);
    //     progress = 100 * cur_size / param.size;
    //     ;
    //     dzlog_debug("ota_download progress = %d", progress);
    //     memset(uid, 0, 64);
    //     GF_GetGUID(uid);
    //     log_res.iMid = uid;
    //     send_progress_V2(115, progress, &log_res); // 平台侧尚未处理该115，所以屏蔽
    // }
    // 等待线程结束
    pthread_join(thread, (void **)&iRet);

    if (info.stop == 1)
    {
        dzlog_error("下载出错：文件中断");
        // 下载中断就删除文件
        remove(param.filename);
        isError = true;
        log_res.code = 202;
        goto Uerror;
    }

    if (*iRet == -1)
    {
        dzlog_error("下载出错：无法连接到或登录到文件服务器");
        isError = true;
        log_res.code = 520;
        goto Uerror;
    }
    else if (*iRet == -2)
    {
        dzlog_error("下载出错：文件服务器无法查询到该文件");
        isError = true;
        log_res.code = 521;

        goto Uerror;
    }
    else if (*iRet == -3)
    {
        dzlog_error("下载出错：文件下载超时或出错");
        isError = true;
        log_res.code = 522;
        goto Uerror;
    }
    else if (*iRet == -4)
    {
        dzlog_error("下载出错：磁盘没有空间");
        isError = true;
        log_res.code = 523;
        goto Uerror;
    }
    else
    {
        // 校验sha256
        if (strcmp(param.digestAlgorithm, "md5") == 0)
        {
            unsigned char hash_md5[MD5_DIGEST_LENGTH * 2 + 1];
            calculate_md5(param.filename, hash_md5);
            if (strcmp(hash_md5, param.digest) != 0)
            {
                log_res.code = 420;
                isError = true;
                remove(param.filename);
                dzlog_error("Verification error:%s", hash_md5);
                goto Uerror;
            }
        }
        else if (strcmp(param.digestAlgorithm, "sha256") == 0)
        {
            unsigned char hash_sha256[SHA256_DIGEST_LENGTH * 2 + 1];
            calculate_file_sha256(param.filename, hash_sha256);
            if (strcmp(hash_sha256, param.digest) != 0)
            {
                log_res.code = 420;
                isError = true;
                remove(param.filename);
                dzlog_error("Verification error:%s", hash_sha256);
                goto Uerror;
            }
        }
        else
        {
            log_res.code = 500;
            isError = true;
            dzlog_error("can not support hash %s", param.digestAlgorithm);
            goto Uerror;
        }
    }
    sleep(1);
    // 下载校验完成
    GF_GetGUID(uid);
    log_res.code = 200;
    log_res.body = "download ok";
    dzlog_info("finish download:%s", param.filename);
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    while (ret < 0)
    {
        ret = IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        sleep(10);
    }
Uerror:
    if (isError)
    {
        GF_GetGUID(uid);
        log_res.body = "update error";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.digest);
    free_s(param.digestAlgorithm);
    free_s(param.fileId);
    free_s(param.fileLink);
    free_s(param.filename);
    free_s(psJson);
    free_s(pcJson);
    free_s(iRet);
    return 0;
}

int dictionary_download(char *pcJson)
{
    // 分线程
    pthread_t thread;
    pthread_attr_t attr;
    char *psJson = strdup(pcJson);
    // 初始化线程属性
    pthread_attr_init(&attr);

    // 将线程设置为分离状态
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

    // 创建线程
    pthread_create(&thread, &attr, dictionary_download_pthread, psJson);
    // 销毁线程属性对象
    pthread_attr_destroy(&attr);
    return 0;
}

/// @brief 文件复制
/// @param pcJson
/// @return
int dictionary_copy(char *pcJson)
{
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_COPY_PARAM param;
    log.param = &param;
    JsonToStruct_CopyFile(pcJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;

    char cmd[1024] = {0};

    if (param.isfile)
    {
        sprintf(cmd, "cp %s %s", param.srcpath, param.descpath);
    }
    else
    {
        sprintf(cmd, "cp  %s %s -R", param.srcpath, param.descpath);
    }

    FILE *fp = popen(cmd, "r");
    if (fp == NULL)
    {
        int error = errno;
        dzlog_error("popen errror:%s", strerror(error));
        isError = true;
        log_res.code = 500;
        goto Uerror;
    }

    log_res.code = 200;
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));

Uerror:
    if (isError)
    {
        log_res.body = "update error";
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.requestID);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(param.descpath);
    free_s(param.srcpath);
    free_s(psJson);
    fclose(fp);
    return 0;
}

/// @brief 获取文件目录的大小
/// @param pcJson
/// @return
int dictionary_GetDicSize(char *pcJson)
{
    /* return 0;*/
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_GETDICSIZE_PARAM param;
    log.param = &param;
    JsonToStruct_GetDicSize(pcJson, &log);

    struct stat file_stat;
    char sizetmp[32] = {0};
    if (lstat(param.path, &file_stat) == -1)
    {
        // 异常，找不到此路径
        int error = errno;
        dzlog_error("getpathinfo %d error %s", param.path, strerror(error));
        return 0;
    }
    char cmdt[263] = {0};
    char buf[32] = {0};
    sprintf(cmdt, "du -sh %s", param.path);
    FILE *fp = popen(cmdt, "r");

    int i = 0;
    while (fgets(buf, 32, fp) != NULL)
    {
        char *p1 = strstr(buf, "\t");
        if (p1)
        {
            *p1 = '\0';
        }
        char *token = strtok(buf, " ");
        if (token != NULL && i == 0)
        {
            strcpy(sizetmp, token);
            dzlog_info("dictionary_GetDicSize 1122 sizetmp[%s]", sizetmp);
        }
        i++;
        token = strtok(NULL, " ");
    }
    int status;
    if (pclose(fp) == -1)
    {
        perror("pclose");
        dzlog_info("get_file_info pclose(fp) error");
    }
    else
    {
        waitpid(-1, &status, 0); // 等待子进程结束
    }

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.zone = log.zone;
    bool isError = false;
    IOTA_DICTIONARY_SIZE file_info;
    strcpy(file_info.path, param.path);
    strcpy(file_info.size, sizetmp);
    log_res.body = &file_info;
    log_res.code = 200;
    StructToJson_GetDictionarySize(&psJson, &log_res);
    IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));

Uerror:
    if (isError)
    {
        log_res.body = "update error";
        StructToJson_GetDictionarySize(&psJson, &log_res);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.Servicename);
    free_s(log.zone);
    free_s(log.node);
    free_s(log.msgTime);
    free_s(log.deviceID);
    free_s(param.path);
    free_s(psJson);
    return 0;
}

/// @brief 文件中断上传下载
/// @param pcJson
/// @param action 1:下载 2:上传
/// @return
int dictionary_break(char *pcJson, int action)
{
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_BREAK_PARAM param;
    log.param = &param;
    JsonToStruct_Break(pcJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.requestID = log.requestID;
    log_res.zone = log.zone;
    bool isError = false;

    int index = -1;

    dzlog_info("dictionary_break progress_info_ptr %p", progress_info_ptr);

    for (int i = 0; i < 20; i++)
    {
        if (progress_info_ptr[i] != NULL)
        {
            if (strcmp(param.filename, progress_info_ptr[i]->filename) == 0)
            {
                dzlog_info("dictionary_break progress_info_ptr %d stop", i);
                progress_info_ptr[i]->stop = 1;
                index = i;
                break;
            }
        }
    }
    if (index == -1)
    {
        isError = true;
        log_res.code = 426;
        goto Uerror;
    }

    log_res.code = 200;
    StructToJson_LogUploadRes(&psJson, &log_res, true);
    IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
Uerror:
    if (isError)
    {
        StructToJson_LogUploadRes(&psJson, &log_res, true);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.requestID);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.node);
    free_s(log.zone);
    free_s(log.msgTime);
    free_s(log.Servicename);
    free_s(param.filename);
    free_s(psJson);
    return 0;
}

int dictionary_commond(char *pcJson)
{
    cJSON *json = NULL;
    char cmd[32] = {0};
    json = cJSON_Parse(pcJson);
    if (json)
    {
        strncpy(cmd, cJSON_GetObjectItem(json, "cmd")->valuestring, sizeof(cmd));
        dzlog_info("dictionary_commond cmd[%s] ", cmd);
        // 告警规则
        if (strstr(cmd, "getDictionaryTree"))
        {
            dictionary_tree(pcJson);
        }
        else if (strstr(cmd, "uploadFile"))
        {
            dictionary_upload(pcJson);
        }
        else if (strstr(cmd, "downloadFile"))
        {
            dictionary_download(pcJson);
        }
        else if (strstr(cmd, "copyFile"))
        {
            dictionary_copy(pcJson);
        }
        else if (strstr(cmd, "deleteFile"))
        {
            dictionary_delete(pcJson);
        }
        else if (strstr(cmd, "getDictionarySize"))
        {
            dictionary_GetDicSize(pcJson);
        }
        else if (strstr(cmd, "breakDownload"))
        {
            dictionary_break(pcJson, 1);
        }
        else if (strstr(cmd, "breakUpload"))
        {
            dictionary_break(pcJson, 2);
        }
        cJSON_Delete(json);
    }
    return 0;
}

int dictionary_delete(char *pcJson)
{
    dzlog_info("dictionary_delete start");
    ST_IOTA_LOG log;
    IOTA_DICTIONARY_PARAM param;
    log.param = &param;
    JsonToStruct_DictionaryDetele(pcJson, &log);

    char *psJson;
    char uid[80] = {0};
    GF_GetGUID(uid);
    ST_IOTA_LOG_RES log_res;
    log_res.body = "";
    log_res.deviceID = log.deviceID;
    log_res.deviceSn = log.deviceSn;
    log_res.iMid = uid;
    log_res.node = log.node;
    log_res.replyId = log.iMid;
    log_res.zone = log.zone;
    log_res.requestID = NULL;
    bool isError = false;
    
    if(param.path==NULL ||param.fileName==NULL)
    {
        int error = errno;
        dzlog_error("Error deleting file NULL error");
        isError = true;
        log_res.code = 400;
        goto Uerror;
    }

    char full_path[1024];
    snprintf(full_path, sizeof(full_path), "%s/%s", param.path, param.fileName);

    if (access(full_path, F_OK) == 0) {
        if (remove(full_path) == 0) {
            dzlog_info("File deleted successfully: %s \n",full_path);
            log_res.code = 200;
            // log_res.body = "delete successfully";
            StructToJson_DictionaryDetele(&psJson, &log_res);

            IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
        } else {
            int error = errno;
            dzlog_error("Error deleting file %s error %s", full_path, strerror(error));
            isError = true;
            // log_res.body = strerror(error);
            log_res.code = 500;
            goto Uerror;
        }
    } else {
        dzlog_info("File does not exist.\n");
    }

Uerror:
    if (isError)
    {
        StructToJson_DictionaryDetele(&psJson, &log_res);
        IOTA_SendMqtt("/v1/devices/dictionary/response", psJson, strlen(psJson));
    }

Ufree:
    free_s(log.iMid);
    free_s(log.deviceSn);
    free_s(log.deviceID);
    free_s(log.msgTime);
    free_s(log.node);
    free_s(log.zone);
    free_s(psJson);
    free_s(param.path);
    free_s(param.fileName);
    return 0; 
}